package com.UdpRecieve.Netty.util.FileApproval;

import com.UdpRecieve.domain.FileReadContent;
import com.UdpRecieve.domain.SysFileType;
import com.UdpRecieve.domain.SysKeyWord;
import org.apache.poi.EmptyFileException;
import org.apache.poi.poifs.filesystem.FileMagic;

import java.io.*;
import java.util.List;
import java.util.Map;

/**
 * 文件合法性检测工具类
 * 对文件进行三方面检测
 * 1. 文件关键字（被检测关键字由管理员设定，存在数据库中）
 * 2. 文件类型检测（允许上传的文件类型由管理员指定，存在数据库中）
 * 3. 文件编码检测
 */
public class FileDetection {

    /**
     * 手动提交审批时文件内容检测
     *
     * @param file         被检测文件
     * @param sysKeyWords  系统关键字
     * @param sysFileTypes 系统文件类型
     * @param fileName     文件名称
     * @return
     */
    public static String detectFile(File file, List<SysKeyWord> sysKeyWords, List<SysFileType> sysFileTypes, String fileName) {
        String fileResult = "合格";
        InputStream is = null;
        try {
            is = new FileInputStream(file);
            // 首先对文件类型进行检测，判断是否是office类
            Map<String, Object> mapResutlt = FileCheckType.getFileType(is);
            // 如果为office类型,判断是否符合系统要求
            if (FileMagic.UNKNOWN != mapResutlt.get("fileMagic")) {
                if (fileName.endsWith(".doc") || fileName.endsWith(".docx")) {
                    String content = FileReadContent.readDoc(new FileInputStream(file), (FileMagic) mapResutlt.get("fileMagic"));
                    if (content == "") {
                        return "非法文件类型";
                    } else {
                        return checkOfficeKeyWord(content, sysKeyWords);
                    }
                } else if (fileName.endsWith(".xls") || fileName.endsWith(".xlsx")) {
                    try {
                        String content = FileReadContent.readExcel(new FileInputStream(file), fileName);
                        if (content == "") {
                            return "非法文件类型";
                        } else {
                            return checkOfficeKeyWord(content, sysKeyWords);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
            InputStream originIS = null;
            try {
                originIS = new FileInputStream(file);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            // 如果文件不为office类型，继续判断
            String type = FileCheckType.getFileType(originIS, sysFileTypes, fileName);

            // 如果返回值为yes,则系统中指定该了类型
            if (type != "yes") {
                if (type != "") {
                    return "非法文件类型";
                }
                if (type == "") { // 未检测到文件真实类型，判断系统是否配置后缀
                    boolean isExist = false;
                    String fileend = fileName.substring(fileName.lastIndexOf(".") + 1);
                    for (SysFileType sysFileType : sysFileTypes) {
                        // 不相等就继续判断
                        String value = sysFileType.getTypeValue();
                        if (!fileend.equalsIgnoreCase(value)) {
                            continue;
                        } else if (fileend.equalsIgnoreCase(value)) {
                            isExist = true;
                            break;
                        }
                    }
                    if(!isExist){
                        return "非法文件类型";
                    }
                }
            }
            // 系统存在该类型，将字节流包装为缓冲流，进行编码检测
            BufferedInputStream bufferedInputStream = null;
            bufferedInputStream = new BufferedInputStream(new FileInputStream(file));

            String code = FileCode.getInputStreamEncode(bufferedInputStream);
            // 如果该文件编码为void，则默认为合格，不进行检查
            if (code == "void") {
                try {
                    bufferedInputStream.close();
                } catch (IOException e) {

                } finally {
                    bufferedInputStream = null;
                }
//                return "不支持检测的文件类型";
                return "合格";
            }
            // 如果未查询到该文件编码，则使用系统默认编码
            if (code == null) {
                code = System.getProperty("file.encoding");
            }
            // 进行文件内容检测
            fileResult = checkTextKeyWord(bufferedInputStream, code, sysKeyWords);
            return fileResult;
        } catch (EmptyFileException e) {
            return "存在空文件";
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            return "不支持检测的文件类型";
        }
        return "";
    }


    /**
     * 根据文件内容检测是否包含关键字（主要用于office类）
     *
     * @param content     文件内容
     * @param sysKeyWords 系统设定关键字
     * @return 检测结果
     */
    private static String checkOfficeKeyWord(String content, List<SysKeyWord> sysKeyWords) {
        String result = "合格";
        for (SysKeyWord sysKeyWord : sysKeyWords) {
            if (content.contains(sysKeyWord.getKeywordValue())) {
                result = "包含非法关键字：" + sysKeyWord.getKeywordValue();
                break;
            }
        }
        return result;
    }

    /**
     * 根据文件流检测是否包含关键字（主要用于文本类）
     *
     * @param bis         文件流
     * @param code        文件编码
     * @param sysKeyWords 系统设定关键字
     * @return 检测结果
     */
    private static String checkTextKeyWord(BufferedInputStream bis, String code, List<SysKeyWord> sysKeyWords) throws UnsupportedEncodingException {
        String result = "合格";
        InputStreamReader read = null;
        try {
            // 获取文件流
            //将字节缓冲流转换为字符输入流
            read = new InputStreamReader(bis, code);
            BufferedReader bufferedReader = new BufferedReader(read);
            String line = null;
//            line = bufferedReader.readLine();
//            System.out.println(line);
//            System.out.println(line = bufferedReader.readLine());
            while ((line = bufferedReader.readLine()) != null) {
                // 判断文件是否包含关键字
                for (SysKeyWord sysKeyWord : sysKeyWords) {
                    // 将使用本地系统编码保存的关键字转换为文件编码
                    String key = new String(sysKeyWord.getKeywordValue().getBytes(System.getProperty("file.encoding")), code);
                    if (line.contains(sysKeyWord.getKeywordValue()) || line.contains(key)) {
                        return "包含非法关键字：" + sysKeyWord.getKeywordValue();
                    }
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
//            InputStream is = inputStreamThreadLocal.get();
            try {
//                is.close();
                bis.close();
                read.close();
            } catch (IOException e) {
//                e.printStackTrace();
            } finally {
                bis = null;
                read = null;
//                is = null;
            }
        }
        return result;
    }

}
